import utils, { NameSpace } from 'utils';
import CONSTANTS from 'utils/constants';
import exceed from 'utils/apimap';
import sha1 from 'sha1';
import { Message } from '@teamix/ui';
import { YunxiaoIcon } from '@alife/devops-ui';
import queryString from 'query-string';
import {
  getMrChangeTree,
  getMrCommits,
  getMrChangeDiff,
  postSingleComment,
  postAllDrafts,
  getAllComments,
  getAllDrafts,
} from 'api';
import {
  getSummaryLogs,
  updateData as updateRootData,
  getCrDetail,
} from 'pages/index/pages/project/pages/projectMergeRequestDetail/actions';
import track from 'utils/track';
import intl from '../../../../../../../../../locale';

const { pathResource, user } = window.FORCE;
const ns = NameSpace('cr_changes');
export const OPEN_CODESCAN_PANEL_FROM_OVERVIEW = ns('OPEN_CODESCAN_PANEL_FROM_OVERVIEW');
// 从overview跳转过来，设置扫描面板中默认搜索项
export const SET_BUILDID = ns('SET_BUILDID');
// 从overview跳转过来，设置评论面板的默认过滤项
export const OPEN_COMMENT_PANEL_FROM_OVERVIEW = ns('OPEN_COMMENT_PANEL_FROM_OVERVIEW');
export const SET_COMMENT_PANNEL_STATUS = ns('SET_COMMENT_PANNEL_STATUS');
export const RESET_CHANGE_DATA = ns('RESET_CHANGE_DATA');
export const CHANGE_ROUTER = ns('CHANGE_ROUTER');
export const RECEIVE_CRDETAIL = ns('RECEIVE_CRDETAIL');
export const LOADING_COMMITSANDDIFFS = ns('LOADING_COMMITSANDDIFFS');
export const RECEIVE_DIFFS = ns('RECEIVE_DIFFS');
export const CHANGE_VIEWTYPE = ns('CHANGE_VIEWTYPE');
export const RECEIVE_INLINE_COMMENTS = ns('RECEIVE_INLINE_COMMENTS');
export const RECEIVE_COMMON_COMMENTS = ns('RECEIVE_COMMON_COMMENTS');
export const RECEIVE_LOGS = ns('RECEIVE_LOGS');
export const RECEIVE_SUMMARY_LOGS = ns('RECEIVE_SUMMARY_LOGS');
export const TOGGLE_MERGECHECKED = ns('TOGGLE_MERGECHECKED');
export const TOGGLE_DELETECHECKED = ns('TOGGLE_DELETECHECKED');
export const ADD_WRITINGCHANGES = ns('ADD_WRITINGCHANGES');
export const ADD_WRITING_YUNDOU_CHANGES = ns('ADD_WRITING_YUNDOU_CHANGES');
export const ADD_WRITINGCHANGESEDITOR = ns('ADD_WRITINGCHANGESEDITOR');
export const REMOVE_WRITINGCHANGESANDEDITOR = ns('REMOVE_WRITINGCHANGESANDEDITOR');
export const REMOVE_WRITING_YUNDOU_CHANGESANDEDITOR = ns('REMOVE_WRITING_YUNDOU_CHANGESANDEDITOR');
export const RECEIVE_PUSHRECORDS = ns('RECEIVE_PUSHRECORDS');
export const UPDATE_PUSH_ID = ns('UPDATE_PUSH_ID');
export const UPDATE_SELECTED_COMMIT_SHA = ns('UPDATE_SELECTED_COMMIT_SHA');
export const RECEIVE_MORE_LINES = ns('RECEIVE_MORE_LINES');
export const RECEIVE_TEST_RESULT = ns('RECEIVE_TEST_RESULT');
export const RECEIVE_P3C_VIOLATIONS = ns('RECEIVE_P3C_VIOLATIONS');
export const RECEIVE_P3C_DETAIL = ns('RECEIVE_P3C_DETAIL');
export const RECEIVE_SINGLE_DIFF = ns('RECEIVE_SINGLE_DIFF');
export const LODING_SINGLE_DIFF = ns('LODING_SINGLE_DIFF');
export const RECEIVE_DIFFS_COUNT = ns('RECEIVE_DIFFS_COUNT');
export const RECEIVE_WORKITEM = ns('RECEIVE_WORKITEM');
export const UPDATE_TREE = ns('UPDATE_TREE');
export const TOGGLE_TREE = ns('TOGGLE_TREE');
export const RECEIVE_UPVOTE = ns('RECEIVE_UPVOTE');
export const RECEIVE_LABELS = ns('RECEIVE_LABELS');
export const RECEIVE_JUMP_LINE_CODE = ns('RECEIVE_JUMP_LINE_CODE');
export const RECEIVE_CHANGE_REQUEST = ns('RECEIVE_CHANGE_REQUEST');
export const RECEIVE_JUMP_FILE = ns('RECEIVE_JUMP_FILE');
export const COMMENT_JUMP_CONNECT = ns('COMMENT_JUMP_CONNECT');
export const FINISH_INTRO = ns('FINISH_INTRO');
export const DELETE_SOURCE_BRANCH = ns('DELETE_SOURCE_BRANCH');
export const CHANGE_COMMENTS_VISIBLE_STATUS = ns('CHANGE_COMMENTS_VISIBLE_STATUS');
export const RECEIVE_INLINE_ISSUES = ns('RECEIVE_INLINE_ISSUES');
export const CHANGE_CODEOWNER_FOCUS_MODE = ns('CHANGE_CODEOWNER_FOCUS_MODE');
export const EXPIRED_COMMIT_SHA = ns('EXPIRED_COMMIT_SHA');

export const UPDATE_DATA = ns('UPDATE_DATA');

export function updateData(data) {
  return (dispatch) => {
    dispatch({
      type: UPDATE_DATA,
      data,
    });
  };
}

export function resetData() {
  return (dispatch) => {
    dispatch({
      type: RESET_CHANGE_DATA,
    });
  };
}

let trackFileInfo;
// 开始浏览文件
function trackFileStart({ fileSha1, state }) {
  const { codeReviewDetail, diffsSha1Map, diffs, from_commit, to_commit } = state;

  if (!(diffs && diffs.length)) {
    return false;
  }

  const activeDiff = diffs.find((diff) => diffsSha1Map[fileSha1] === diff.new_path);

  if (!activeDiff) {
    return false;
  }

  trackFileInfo = {
    timeStart: +new Date(),
    mr_id: codeReviewDetail.id,
    from_commit,
    to_commit,
    new_object_id: activeDiff.new_object_id,
    filePath: activeDiff.new_path,
    hiddenDuring: 0, // 视窗非活跃的时长
    hiddenAt: 0, // 用于计算视窗非活跃的时长
  };
}
// 结束浏览文件，并打点
function trackFileEnd() {
  if (trackFileInfo) {
    const now = +new Date();
    trackFileInfo = {
      ...trackFileInfo,
      timeEnd: now,
      duration: now - trackFileInfo.timeStart - trackFileInfo.hiddenDuring,
    };

    track({
      action: 'visit_file_time',
      page: 'Repo-MR-changes',
      type: '',
      control: '',
      projectId: window.FORCE.pathResource ? window.FORCE.pathResource.id : '',
      path: trackFileInfo.filePath,
      mr_id: trackFileInfo.mr_id,
      from_commit: trackFileInfo.from_commit,
      to_commit: trackFileInfo.to_commit,
      new_object_id: trackFileInfo.new_object_id,
      duration: trackFileInfo.duration / 1000,
      user_id: window.FORCE.user ? window.FORCE.user.codeUserId : '',
      tb_user_id: window.FORCE.user ? window.FORCE.user.id : '',
    });

    trackFileInfo = null;
  }
}
// 点击通过是也打点
export function trackViewFileAtAccept() {
  return () => {
    trackFileEnd();
  };
}

// 监听视窗 visibilitychange 事件，计算浏览一个文件时的非活跃时长
try {
  document.addEventListener('visibilitychange', handleVisibilityChange, false);
} catch (error) {
  console.error(
    intl.get({
      id: 'code-assets.changes.actions.VisibilitychangeEventMonitoringFailed',
      defaultMessage: 'visibilitychange 事件监听失败',
    }),
  );
  console.error(error);
}
function handleVisibilityChange() {
  if (trackFileInfo) {
    const isPageActive = !document.hidden;
    const now = +new Date();

    if (isPageActive && trackFileInfo.hiddenAt) {
      trackFileInfo.hiddenDuring += now - trackFileInfo.hiddenAt;
    } else {
      trackFileInfo.hiddenAt = now;
    }
  }
}

export function getScrollTrackTime(fileSha1) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    if (trackFileInfo) {
      trackFileEnd();
    }
    trackFileStart({ fileSha1, state });
  };
}

// 自己实现的路由
export function changeRouter(hash) {
  return (dispatch, getState) => {
    // 单文件浏览模式下，切换文件时进行文件浏览时长埋点
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const hashObj = queryString.parse(hash);

    if (state.forceCrFileViewType === 'single') {
      if (hashObj.file) {
        // 结束上一个文件记录
        trackFileEnd();
        // 开始新文件记录
        trackFileStart({ fileSha1: hashObj.file, state });
        console.error(trackFileStart, 'trackFileStart');
      } else {
        // 结束上一个文件记录（如有）
        trackFileEnd();
      }
    }

    // 版本号发生变化时，需要重新请求数据，有两种情况，1、版本号在commits区间内，2、不在区间内,需要显示一个异常文本
    if (
      hashObj.from_commit &&
      hashObj.to_commit &&
      !(hashObj.from_commit === state.from_commit && hashObj.to_commit === state.to_commit)
    ) {
      const hasToCommit = state.commits.some((item) => {
        return item.id === hashObj.to_commit;
      });
      if (hasToCommit) {
        updateData({
          from_commit: hashObj.from_commit,
          to_commit: hashObj.to_commit,
          isTogglingCommits: true,
          isShowExpiredPage: false,
        })(dispatch);
        // 获取树结构以及右侧文件diff
        dispatch(getPushRecordsDiff());
        dispatch(getTotalComments());
        dispatch(getDrafts());
      } else {
        updateData({
          isShowExpiredPage: true,
        })(dispatch);
      }
    }

    dispatch({
      type: CHANGE_ROUTER,
      data: hash,
    });
  };
}

// ahead>0 and COUNT(commit)=0 定时查询commits
export function getExactCommitsPromise(ahead) {
  let timer = null;
  return new Promise((resolve, reject) => {
    const func = () => {
      getMrCommits()
        .then((result) => {
          const srcCommits = result.slice(1);
          if (!!ahead && !srcCommits.length) {
            timer = setTimeout(() => {
              func();
            }, 1000);
          } else {
            clearTimeout(timer);
            resolve(result);
          }
        })
        .catch((err) => {
          clearTimeout(timer);
          reject(err);
        });
    };
    func();
  });
}

// 获取commits区间
export function getCommitsRange(cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { mr_ahead_behind_info } = getState().project.projectMergeRequestDetail.root;
    const ahead = mr_ahead_behind_info ? mr_ahead_behind_info.ahead : 0;
    updateData({
      isLoadingCommits: true,
    })(dispatch);
    getExactCommitsPromise(ahead)
      .then((result) => {
        const srcCommits = result.slice(1);
        cb && cb(srcCommits);
        const commits = srcCommits.map((item) => {
          item.sha = item.sha || item.id;
          return item;
        });
        const lastCommit = commits[commits.length - 1] || {};

        updateData({
          commits,
          lastCommit,
          // 如果hash中带有commit信息，不需要更新
          from_commit: state.from_commit || (commits[0] && commits[0].sha) || '',
          to_commit: state.to_commit || (lastCommit && lastCommit.sha) || '',
          isLoadingCommits: false,
          isPushRecordsFetched: true,
        })(dispatch);
        // 获取树结构以及右侧文件diff
        dispatch(getPushRecordsDiff());
        dispatch(getTotalComments());
        dispatch(getDrafts());
      })
      .catch((err) => {
        updateData({
          isLoadingCommits: false,
        })(dispatch);
        console.error(err);
      });
  };
}

// 切换视图、忽略空白、展示形式
export function toggleViewAndDiffAndIgnoreWhiteSpace(data) {
  return (dispatch) => {
    updateData(data)(dispatch);
    data.forceDiffViewType !== undefined &&
      utils.setCachedData('forceDiffViewType', data.forceDiffViewType);
    data.forceCrFileViewType !== undefined &&
      utils.setCachedData('forceCrFileViewType', data.forceCrFileViewType);
    data.forceIgnoreWhitespace !== undefined &&
      utils.setCachedData('forceIgnoreWhitespace', data.forceIgnoreWhitespace);
    data.commentsVisibleStatus !== undefined &&
      utils.setCachedData('commentsVisibleStatus', data.commentsVisibleStatus);
    // 只有忽略空白重新加载diff
    Object.keys(data).includes('forceIgnoreWhitespace') && dispatch(getPushRecordsDiff());
  };
}

// 获取push区块的diff
export function getPushRecordsDiff(cb) {
  return (dispatch, getState) => {
    updateData({
      isLoadingDiffTree: true,
      getTreeFailReason: '',
      getTreeFailError: {},
    })(dispatch);

    // 先获取changesets
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { forceIgnoreWhitespace, from_commit, to_commit, totalCountInfo } = state;

    getMrChangeTree({
      from_commit: from_commit || to_commit,
      to_commit: to_commit || from_commit,
    })
      .then((result) => {
        const changesets = result.changesetDTOS;
        updateData({
          isLoadingDiffTree: false,
          totalCountInfo: {
            ...totalCountInfo,
            curFileCount: result.count,
            curLineCount: (result.totalAddLines || 0) + (result.totalDelLines || 0),
            isTotalCountLoaded: true,
          },
        })(dispatch);

        dispatch({
          type: RECEIVE_DIFFS_COUNT,
          data: {
            additions: result.totalAddLines,
            deletions: result.totalDelLines,
          },
        });

        // 再获取changesets内的diffs内容
        // 如果大于 MAX_CR_DIFF_NUM 个diff文件，则不自动加载内容，让用户手动点击加载
        if (changesets.length < CONSTANTS.MAX_CR_DIFF_NUM) {
          const allPromise = changesets.map((diff) => {
            let params;
            if (from_commit || to_commit) {
              params = {
                ref: '',
                from_commit: from_commit || to_commit,
                to_commit: to_commit || from_commit,
                old_path: diff.old_path,
                new_path: diff.new_path,
                context: 3,
                include_extra_info_lines: true,
                ignore_whitespace: forceIgnoreWhitespace,
                mode: '',
              };
            } else {
              params = {
                ref: diff.ref,
                from_commit: '',
                to_commit: '',
                old_path: '',
                new_path: '',
                context: 3,
                include_extra_info_lines: true,
                ignore_whitespace: forceIgnoreWhitespace,
                mode: '',
              };
            }
            return getMrChangeDiff(params);
          });
          Promise.all(allPromise).then((diffs) => {
            changesets.forEach((changeset, i) => {
              const diffContent = diffs[i].diff;
              // 如果 showDiff: false 表示二进制等无法展示的文件
              changeset.showDiff = diffs[i].showDiff;

              // 如果单个diff大小大于 MAX_CR_DIFF_NUM，则不自动加载内容，让用户手动点击加载
              if (diffContent.length < CONSTANTS.MAX_CR_DIFF_SIZE) {
                changeset.diff = diffContent;
              } else {
                changeset.diff = '$WAITING_FOR_CLICK_BIG_SIZE$';
              }
            });

            dispatch({
              type: RECEIVE_DIFFS,
              data: changesets,
            });

            cb && cb();
          });
        } else {
          changesets.forEach((changeset) => {
            changeset.diff = '$WAITING_FOR_CLICK$';
            changeset.showDiff = true;
          });

          dispatch({
            type: RECEIVE_DIFFS,
            data: changesets,
          });

          cb && cb();
        }
      })
      .catch((err) => {
        // 文件树请求失败时，将失败原因展示
        let errCause = '';
        let errRes = {};
        try {
          errRes = JSON.parse(err.responseText);
          errCause = errRes.message;
        } catch (e) {
          console.error(e);
        }
        updateData({
          isLoadingDiffTree: false,
          isCommitsAndDiffsLoading: false,
          getTreeFailReason: errCause,
          getTreeFailError: errRes,
        })(dispatch);
        console.error(err);
      });
  };
}

// 重新获取并更新树，主要是发表评论或评论改状态后调用
export function updateTree(cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { from_commit, to_commit } = state;

    getMrChangeTree({
      from_commit: from_commit || to_commit,
      to_commit: to_commit || from_commit,
    }).then((result) => {
      const changesets = result.changesetDTOS;
      dispatch({
        type: UPDATE_TREE,
        data: changesets,
      });

      cb && cb();
    });
  };
}

export function rangePromise(
  { params, data },
  { mr_id, push_record_id, changeset_id, file_path, repo, commit },
) {
  const trackData = {
    app: 'linguist',
    action: 'ranges',
    page: 'mr',
    user_id: user && user.id,
    type: '',
    control: '',
    repo,
    branch: '',
    commit,
    file_path,
    mr_id,
    push_record_id,
    changeset_id,
  };

  return new Promise((resolve) => {
    exceed
      .fetch({
        api: 'project.file.ls.scope_ranges',
        params,
        data,
      })
      .then((result) => {
        resolve({
          ...result,
          trackData,
        });
      })
      .fail(() => {
        resolve({
          success: false,
          trackData,
        });
      });
  });
}

// 单独获取单个diff内容，用于用户手动点击加载
export function getSingleDiff(diff) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { forceIgnoreWhitespace, from_commit, to_commit } = state;

    // 将该diff置为loading状态
    dispatch({
      type: LODING_SINGLE_DIFF,
      data: {
        ...diff,
      },
    });

    let params;
    if (from_commit || to_commit) {
      params = {
        ref: '',
        from_commit: from_commit || to_commit,
        to_commit: to_commit || from_commit,
        old_path: diff.old_path,
        new_path: diff.new_path,
        context: 3,
        include_extra_info_lines: true,
        ignore_whitespace: forceIgnoreWhitespace,
        mode: '',
      };
    } else {
      // from_commit to_commit均没有，则不需要请求
      return;
    }

    getMrChangeDiff(params).then((result) => {
      dispatch({
        type: RECEIVE_SINGLE_DIFF,
        data: {
          ...diff,
          diff: result.diff,
          // 如果 showDiff: false 表示二进制等无法展示的文件
          showDiff: result.showDiff,
          is_new_lfs: result.is_new_lfs,
          is_old_lfs: result.is_old_lfs,
        },
      });
      // 如果该文件未读，则置为已读
      if (!diff.read) {
        dispatch(markFileAsRead(diff.deleted_file ? diff.old_object_id : diff.new_object_id));
      }
      // 开始新文件记录
      if (!trackFileInfo && state.hash.tab !== 'changes') {
        trackFileStart({ fileSha1: sha1(diff.new_path), state });
      }
    });
  };
}

// 获取某次 commit 的 diff
export function getCommitDiffs(sha, cb) {
  return (dispatch) => {
    // 清空首尾 push_id
    dispatch({
      type: UPDATE_PUSH_ID,
      data: {
        from_push_id: null,
        to_push_id: null,
      },
    });

    // 更新选中的 commit sha
    dispatch({
      type: UPDATE_SELECTED_COMMIT_SHA,
      data: sha,
    });

    exceed
      .forceFetch({
        api: 'projects.commit.diff',
        params: {
          projectId: pathResource.id,
          sha,
        },
      })
      .then((result) => {
        const pushRecords = result.list;
        dispatch({
          type: RECEIVE_DIFFS,
          data: pushRecords,
        });

        cb && cb();
      });
  };
}

// 获取所有评论
export function getTotalComments(cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { from_commit, to_commit, diffs } = state;
    getAllComments({
      from_commit: from_commit || to_commit || '',
      to_commit: to_commit || from_commit || '',
    })
      .then((result) => {
        updateData({
          localComments: result,
        })(dispatch);
        const data = handleTotalComments(result.slice(1), diffs);
        updateData({
          ...data,
        })(dispatch);

        cb && cb(data);
      })
      .catch((err) => {
        console.error(err);
      });
  };
}

export function getTotalCommentsFromLocal(comment) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { localComments, diffs } = state;
    const newLocalComments = localComments.concat(comment);
    updateData({
      localComments: newLocalComments,
    })(dispatch);
    const data = handleTotalComments(newLocalComments.slice(1), diffs);
    updateData({
      ...data,
    })(dispatch);
  };
}

function handleTotalComments(result, diffs) {
  if (!(result && Array.isArray(result))) {
    return {
      allComments: [],
      inline_comments: [],
      conversations: [],
      diffsConversationsMap: {},
    };
  }

  const inline_comments = result.filter((item) => {
    return !!item.path;
  });

  // 递归形成讨论块：以无parent_note_id的评论作为讨论块的跟节点，其子评论平铺在下面
  const conversations = [];
  inline_comments.forEach((comment) => {
    const isRoot = !comment.parent_note_id;
    if (isRoot) {
      conversations.push([comment]);
    } else {
      conversations.forEach((conversation) => {
        conversation.forEach((childItem) => {
          if (childItem.id === comment.parent_note_id) {
            conversation.push(comment);
          }
        });
      });
    }
  });

  // 按diffs路径名归类的讨论
  const diffsConversationsMap = {};
  if (diffs) {
    diffs.forEach((diff) => {
      diffsConversationsMap[diff.new_path] = [];
      conversations.forEach((conversation) => {
        if (conversation[0].path === diff.new_path) {
          diffsConversationsMap[diff.new_path].push(conversation);
        }
      });
    });
  }

  return {
    allComments: result,
    inline_comments,
    conversations,
    diffsConversationsMap,
  };
}

// 获取mr行内评论
export function getInlineComments(cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.inline_comments',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },
      })
      .then((result) => {
        dispatch({
          type: RECEIVE_INLINE_COMMENTS,
          data: result,
        });

        cb && cb();
      });
  };
}

// 获取评论草稿
export function getDrafts(cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { from_commit, to_commit } = state;
    getAllDrafts({
      from_commit: from_commit || to_commit || '',
      to_commit: to_commit || from_commit || '',
    })
      .then((result) => {
        updateData({
          drafts: result.slice(1) || [],
        })(dispatch);

        cb && cb();
      })
      .catch((err) => {
        console.error(err);
      });
  };
}

// 保存单个评论或者草稿
export function postInlineComments(params, cb) {
  return (dispatch, getState) => {
    const { root } = getState().project.projectMergeRequestDetail;
    if (!params.note.trim()) {
      Message.error({
        title: intl.get({
          id: 'code-assets.changes.actions.TheCommentContentMustBe',
          defaultMessage: '评论内容不能为空',
        }),
      });

      return false;
    }

    const yudouParams = {
      note: params.note,
      issue_id: params.issue_id,
      is_draft: params.is_draft,
    };

    // 云豆回复只传3个参数
    postSingleComment(params.issue_id ? yudouParams : params)
      .then((data) => {
        setTimeout(() => {
          Message.success({
            title: intl.get({
              id: 'code-assets.changes.actions.CommentsSubmittedSuccessfully',
              defaultMessage: '评论提交成功',
            }),
          });
        }, 500);
        cb && cb();
        dispatch(updateTree());
        if (params.issue_id) {
          dispatch(getTotalComments());
        } else if (!params.is_draft) {
          dispatch(getTotalCommentsFromLocal(data));
        }
        dispatch(getDrafts());
        // 更新log
        dispatch(getSummaryLogs());
        // params.issue_id表示是回复云豆，需要更新数据
        if (params.issue_id && !params.is_draft) {
          const { issueDetailList } = root;
          issueDetailList.forEach((item) => {
            if (item.id === params.issue_id) {
              item.comments.push(data);
            }
          });
          dispatch(
            updateRootData({
              issueDetailList,
            }),
          );
        }
        dispatch(getCrDetail()); // 为了刷新可通过的状态
      })
      .catch((err) => {
        console.error(err);
      });
  };
}

// 提交所有草稿
export function postDrafts(note, cb) {
  return (dispatch, getState) => {
    const { root } = getState().project.projectMergeRequestDetail;
    postAllDrafts({ note })
      .then(() => {
        setTimeout(() => {
          Message.success({
            title: intl.get({
              id: 'code-assets.changes.actions.DraftSubmittedSuccessfully',
              defaultMessage: '草稿提交成功',
            }),
          });
        }, 500);
        cb && cb();

        dispatch(updateTree());
        dispatch(
          getTotalComments((data) => {
            // 提交草稿后，更新扫描数据
            const { issueDetailList } = root;
            const { allComments } = data;

            issueDetailList.forEach((item) => {
              const matchedComments = allComments.filter((comment) => {
                return comment.issue && item.id === comment.issue.id;
              });
              item.comments = matchedComments;
            });
            dispatch(
              updateRootData({
                issueDetailList,
              }),
            );
          }),
        );
        dispatch(getDrafts());
        dispatch(updateTree());
        // 更新log
        dispatch(getSummaryLogs());
      })
      .catch((err) => {
        console.error(err);
      });
  };
}

// 修改草稿内容
export function updateDraft({ noteId, note }) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.comment.update',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
          noteId,
        },

        data: {
          draftFlag: true,
          body: note,
        },
      })
      .then(() => {
        Message.success({
          title: intl.get({
            id: 'code-assets.changes.actions.DraftUpdated',
            defaultMessage: '草稿更新成功',
          }),
        });

        dispatch(getDrafts());
      });
  };
}

// 删除草稿内容
export function deleteDraft(noteId) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.delete_draft',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
          id: noteId,
        },
      })
      .then(() => {
        dispatch(getDrafts());
      });
  };
}

export function toggleMergeChecked() {
  return {
    type: TOGGLE_MERGECHECKED,
  };
}
export function toggleDeleteChecked() {
  return {
    type: TOGGLE_DELETECHECKED,
  };
}

// 添加正在编辑的行
export function addWritingChanges(key) {
  return {
    type: ADD_WRITINGCHANGES,
    data: key,
  };
}

// 添加正在编辑的行对应的编辑器
export function addWritingChangesEditor(key) {
  return {
    type: ADD_WRITINGCHANGESEDITOR,
    data: key,
  };
}

// 删除正在评论的行标识
export function removeWritingChangesAndEditor(key) {
  return {
    type: REMOVE_WRITINGCHANGESANDEDITOR,
    data: key,
  };
}

// 获取两行之间的文件内容
export function loadMoreLines({ hunk, diff, from, to, isAddToEnd, isLoadEndFinished }) {
  return (dispatch, getState) => {
    // TODO 这里接口需要变更，所以暂时写死最近的commit sha
    const { lastCommit, from_commit, to_commit, isLoadingMoreLine } =
      getState().project.projectMergeRequestDetail.changesReducer;
    if (isLoadingMoreLine) {
      return;
    }
    dispatch(
      updateData({
        isLoadingMoreLine: true,
      }),
    );

    exceed
      .forceFetch({
        api: 'projects.blobs.v4',
        params: { projectId: pathResource.id },
        data: {
          filepath: diff.newPath,
          from,
          to,
          // 如果代码评审是展示全部，那么ref传lastCommit.sha；如果是commits对比视图，那么传递commits区间的最后一个commit.sha
          ref: to_commit || from_commit || lastCommit.sha,
        },
      })
      .then((result) => {
        dispatch({
          type: RECEIVE_MORE_LINES,
          data: {
            hunk,
            diff,
            blob: result.content,
            from,
            to,
            isAddToEnd,
            isLoadEndFinished,
          },
        });
      });
  };
}

// 获取mr的p3c扫描结果
export function getMrP3cViolations() {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail, pushRecords } = state;
    exceed
      .forceFetch({
        api: 'project.mr.p3cViolations',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },

        data: {
          from_push_id: pushRecords[0].id,
          to_push_id: pushRecords[pushRecords.length - 1].id,
        },
      })
      .then((result) => {
        const p3cViolations = result.list;
        dispatch({
          type: RECEIVE_P3C_VIOLATIONS,
          data: p3cViolations,
        });
      });
  };
}

// 获取mr的行内问题（由第三方扫描工具接入提供）
export function getMrInlineIssue() {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.inline_issues',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },
      })
      .then((result) => {
        const inlineIssues = result.check_results;
        dispatch({
          type: RECEIVE_INLINE_ISSUES,
          data: inlineIssues,
        });
      });
  };
}

// 获取mr的p3c扫描结果
export function getTestResult() {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { lastCommit } = state;

    exceed
      .forceFetch({
        api: 'projects.testResult',
        params: {
          repoPath: pathResource.fullPath,
          commitId: lastCommit.sha,
        },
      })
      .then((result) => {
        dispatch({
          type: RECEIVE_TEST_RESULT,
          data: result.list,
        });
      });
  };
}

// 获取mr的p3c扫描结果
export function getP3cDetail(id, cb) {
  return (dispatch) => {
    exceed
      .forceFetch({
        api: 'p3c.getById',
        params: {
          id,
        },
      })
      .then((result) => {
        dispatch({
          type: RECEIVE_P3C_DETAIL,
          data: result,
        });

        cb && cb();
      });
  };
}

// 跳到下一个diff文件
export function goNextDiff(toHaveComment) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { mrTabKey } = getState().project.projectMergeRequestDetail.root;
    if (mrTabKey !== 'changes') {
      return;
    }
    const { diffs, diffsSha1Map, hash, diffsConversationsMap } = state;
    const { file } = hash;

    let currentDiffIndex;
    if (file) {
      const currentPath = diffsSha1Map[file];
      currentDiffIndex = diffs.findIndex((item) => item.new_path === currentPath);
    } else {
      currentDiffIndex = 0;
    }

    const nextDiffIndex = currentDiffIndex + 1;
    if (nextDiffIndex < diffs.length) {
      let fileSha;
      if (toHaveComment) {
        for (let i = nextDiffIndex; i < diffs.length; i++) {
          if (diffsConversationsMap[diffs[i].new_path].length) {
            fileSha = sha1(diffs[i].new_path);
            break;
          }
        }
        if (!fileSha) {
          Message.notice({
            title: intl.get({
              id: 'code-assets.changes.actions.ThereIsNoNextDiscussion',
              defaultMessage: '没有下一个讨论了',
            }),
            duration: 2000,
            icon: <YunxiaoIcon type="question-line" style={{ color: '#ffab00' }} />,
          });
        } else {
          window.location = `#file=${fileSha}`;
        }
      } else {
        fileSha = sha1(diffs[nextDiffIndex].new_path);
        window.location = `#file=${fileSha}`;
      }
    } else if (toHaveComment) {
      Message.notice({
        title: intl.get({
          id: 'code-assets.changes.actions.ThereIsNoNextDiscussion',
          defaultMessage: '没有下一个讨论了',
        }),
        duration: 2000,
        icon: <YunxiaoIcon type="question-line" style={{ color: '#ffab00' }} />,
      });
    } else {
      Message.notice({
        title: intl.get({
          id: 'code-assets.changes.actions.ThereIsNoNextFile',
          defaultMessage: '没有下一个文件了',
        }),
      });
    }
  };
}

// 跳到上一个diff文件
export function goPreviousDiff(toHaveComment) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { mrTabKey } = getState().project.projectMergeRequestDetail.root;
    if (mrTabKey !== 'changes') {
      return;
    }
    const { diffs, diffsSha1Map, hash, diffsConversationsMap } = state;
    const { file } = hash;

    let currentDiffIndex;
    if (file) {
      const currentPath = diffsSha1Map[file];
      currentDiffIndex = diffs.findIndex((item) => item.new_path === currentPath);
    } else {
      currentDiffIndex = 0;
    }

    const previousDiffIndex = currentDiffIndex - 1;
    if (previousDiffIndex >= 0) {
      let fileSha;
      if (toHaveComment) {
        for (let i = previousDiffIndex; i >= 0; i--) {
          if (diffsConversationsMap[diffs[i].new_path].length) {
            fileSha = sha1(diffs[i].new_path);
            break;
          }
        }
        if (!fileSha) {
          Message.notice({
            title: intl.get({
              id: 'code-assets.changes.actions.ThereIsNoPreviousDiscussion',
              defaultMessage: '没有上一个讨论了',
            }),
            duration: 2000,
            icon: <YunxiaoIcon type="question-line" style={{ color: '#ffab00' }} />,
          });
        } else {
          window.location = `#file=${fileSha}`;
        }
      } else {
        fileSha = sha1(diffs[previousDiffIndex].new_path);
        window.location = `#file=${fileSha}`;
      }
    } else if (toHaveComment) {
      Message.notice({
        title: intl.get({
          id: 'code-assets.changes.actions.ThereIsNoPreviousDiscussion',
          defaultMessage: '没有上一个讨论了',
        }),
        duration: 2000,
        icon: <YunxiaoIcon type="question-line" style={{ color: '#ffab00' }} />,
      });
    } else {
      Message.notice({
        title: intl.get({
          id: 'code-assets.changes.actions.ThereIsNoPreviousFile',
          defaultMessage: '没有上一个文件了',
        }),
      });
    }
  };
}

// 跳到下一个讨论
export function jumpToNextComment(id) {
  return (dispatch) => {
    // const state = getState().project.projectMergeRequestDetail.changesReducer;
    // const { diffsConversationsMap } = state;

    const $conversations = document.querySelectorAll('.conversation-anchor');

    let thisCommentIndex;
    $conversations.forEach((item, index) => {
      const anchor = item.getAttribute('id');
      if (`anchor_conversation_${id}` === anchor) {
        thisCommentIndex = index;
      }
    });

    const nextAnchorDom = $conversations[thisCommentIndex + 1];
    if (nextAnchorDom) {
      // 先滚到最上面
      document.getElementById('mr-content-body').scrollTop = 0;
      console.log(
        intl.get({
          id: 'code-assets.changes.actions.ThereIsTheNextDiscussion',
          defaultMessage: '============有下一个讨论dom===========',
        }),
      );
      const hasAoneNoticeBar = document.querySelector('.has-aonel-notice');
      const aoneNavHeight = hasAoneNoticeBar ? 70 : 45;
      document.getElementById('mr-content-body').scrollTop =
        nextAnchorDom.getBoundingClientRect().top - aoneNavHeight - 42;
    } else {
      dispatch(goNextDiff('toHaveComment'));
    }
  };
}

// 跳到上一个讨论
export function jumpToPreviousComment(id) {
  return (dispatch) => {
    const $conversations = document.querySelectorAll('.conversation-anchor');

    let thisCommentIndex;
    $conversations.forEach((item, index) => {
      const anchor = item.getAttribute('id');
      if (`anchor_conversation_${id}` === anchor) {
        thisCommentIndex = index;
      }
    });

    const prevAnchorDom = $conversations[thisCommentIndex - 1];
    if (prevAnchorDom) {
      // 先滚到最上面
      document.getElementById('mr-content-body').scrollTop = 0;
      console.log(
        intl.get({
          id: 'code-assets.changes.actions.WithADom',
          defaultMessage: '============有上一个讨论dom===========',
        }),
      );
      const hasAoneNoticeBar = document.querySelector('.has-aonel-notice');
      const aoneNavHeight = hasAoneNoticeBar ? 70 : 45;
      document.getElementById('mr-content-body').scrollTop =
        prevAnchorDom.getBoundingClientRect().top - aoneNavHeight - 42;
    } else {
      dispatch(goPreviousDiff('toHaveComment'));
    }
  };
}

// 左侧树展示与否切换
export function toggleTree() {
  return (dispatch) => {
    dispatch({
      type: TOGGLE_TREE,
    });
  };
}

// 获取赞的人列表
export function getUpvote() {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.upvote.get',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },
      })
      .then((result) => {
        dispatch({
          type: RECEIVE_UPVOTE,
          data: result,
        });
      });
  };
}

// 更新待消费的跳转行号
export function updateJumpLineCode(jump_line_code) {
  return (dispatch) => {
    dispatch({
      type: RECEIVE_JUMP_LINE_CODE,
      data: jump_line_code,
    });
  };
}

// 更新待消费的跳转文件
export function updateJumpFile(file) {
  return (dispatch) => {
    dispatch({
      type: RECEIVE_JUMP_FILE,
      data: file,
    });
  };
}

// 跳转消费评论
export function commentJump(file) {
  return (dispatch) => {
    dispatch({
      type: COMMENT_JUMP_CONNECT,
      data: file,
    });
  };
}

// 用户引导结束
export function finishIntro() {
  return (dispatch) => {
    dispatch({
      type: FINISH_INTRO,
    });
  };
}

// 标记文件为已读
export function markFileAsRead(object_id, cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;

    exceed
      .forceFetch({
        api: 'project.mr.mark_as_read',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },

        data: {
          object_id,
        },
      })
      .then(() => {
        dispatch(updateTree(cb));
      });
  };
}

// 标记文件为未读
export function markFileAsUnRead(object_id, cb) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;

    exceed
      .forceFetch({
        api: 'project.mr.mark_as_unread',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
        },

        data: {
          object_id,
        },
      })
      .then(() => {
        dispatch(updateTree());
        cb && cb();
      });
  };
}

// 删除分支接口
export function deleteSourceBranch() {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;

    exceed
      .fetch({
        api: 'project.branches.delete',
        params: {
          projectId: pathResource.id,
          branch: utils.revisionEncodeURI(codeReviewDetail.source_branch),
        },
      })
      .then(() => {
        Message.success({
          title: intl.get({
            id: 'code-assets.changes.actions.Deleted',
            defaultMessage: '删除成功',
          }),
        });

        dispatch({
          type: DELETE_SOURCE_BRANCH,
        });
      })
      .fail(console.log);
  };
}

// 切换评论隐藏状态
export function changeCommentsVisibleStatus(data) {
  return (dispatch) => {
    dispatch({
      type: CHANGE_COMMENTS_VISIBLE_STATUS,
      data,
    });
  };
}

// 切换 CodeOwner专注模式（select切换）
// export function changeCodeOwnerFocusMode(data) {
//   return (dispatch, getState) => {
//     const state = getState().project.projectMergeRequestDetail.changesReducer;
//     const { from_push_id, to_push_id } = state;
//     dispatch({
//       type: CHANGE_CODEOWNER_FOCUS_MODE,
//       data,
//     });
//     dispatch(
//       getPushRecordsDiff({
//         from_push_id,
//         to_push_id,
//       })
//     );
//   };
// }

// 更改评论状态（close/reopen）
export function toggleComment({ noteId, closed }) {
  return (dispatch, getState) => {
    const state = getState().project.projectMergeRequestDetail.changesReducer;
    const { codeReviewDetail } = state;
    exceed
      .forceFetch({
        api: 'project.mr.comment.update',
        params: {
          projectId: pathResource.id,
          mrId: codeReviewDetail.id,
          noteId,
        },

        data: {
          closed: closed ? 1 : 0,
        },
      })
      .then(() => {
        dispatch(getTotalComments());
        dispatch(updateTree());
        dispatch(getSummaryLogs());
        dispatch(getCrDetail()); // 为了刷新可通过的状态
      });
  };
}
